CloudFormationでService Catalogの製品を起動してみた
AWS事業本部コンサルティング部のイシザワです。
CloudFormationからService Catalogの製品を起動することができるようなので、実際に試してみました。 作成したテンプレートから製品を作成することで、他製品を起動する製品を作成してみます。
テンプレート
以下のコード断片が製品の起動を行う箇所になります。
Resources: Network: Type: AWS::ServiceCatalog::CloudFormationProvisionedProduct Properties: ProductName: NetworkComponent ProvisioningArtifactName: !Ref NetworkComponentVersion ProvisioningParameters: - Key: SystemId Value: !Ref SystemId - Key: VpcCidr Value: !Ref VpcCidr
ProductName
で製品名を指定します。製品名で製品を特定できない場合(同じ製品名の製品がある場合)は、ProductId
に製品IDを指定することで製品を特定します。
ProvisioningArtifactName
で製品のバージョン名を指定します。製品名と同様にバージョン名でバージョンを特定できない場合は、ProvisioningArtifactId
にバージョンIDを指定することでバージョンを特定します。
ProvisioningParameters
は製品に渡すパラメータです。
起動する製品はこのテンプレートのプロビジョニングを実行するプリンシパルから起動可能である必要があります。 つまり、製品はそのプリンシパルからアクセス可能なポートフォリオに含まれている必要があります。
使用感としてはネストスタックとほとんど同じで、Outputsアトリビュートで製品のOutputを参照することができます。
以下がテンプレートの全体です。このテンプレートは2層構造のWebシステムを作成します。起動する製品のバージョン名をパラメータとして受け取ることでユーザー側で製品の個別更新を行えるようにしています。
AWSTemplateFormatVersion: 2010-09-09 Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Global Configuration Parameters: - SystemId - Label: default: Network Configuration Parameters: - NetworkComponentVersion - VpcCidr - Label: default: Security Group Configuration Parameters: - SecurityGroupComponentVersion - Label: default: Web Server Configuration Parameters: - WebServerComponentVersion - Label: default: Database Configuration Parameters: - DatabaseComponentVersion - DatabaseAdminUserPassword Parameters: SystemId: Type: String Default: sample NetworkComponentVersion: Type: String SecurityGroupComponentVersion: Type: String WebServerComponentVersion: Type: String DatabaseComponentVersion: Type: String VpcCidr: Type: String DatabaseAdminUserPassword: Type: String NoEcho: true Resources: Network: Type: AWS::ServiceCatalog::CloudFormationProvisionedProduct Properties: ProductName: NetworkComponent ProvisioningArtifactName: !Ref NetworkComponentVersion ProvisioningParameters: - Key: SystemId Value: !Ref SystemId - Key: VpcCidr Value: !Ref VpcCidr SecurityGroup: Type: AWS::ServiceCatalog::CloudFormationProvisionedProduct Properties: ProductName: SecurityGroupComponent ProvisioningArtifactName: !Ref SecurityGroupComponentVersion ProvisioningParameters: - Key: SystemId Value: !Ref SystemId - Key: VpcId Value: !GetAtt Network.Outputs.VpcId WebServer: Type: AWS::ServiceCatalog::CloudFormationProvisionedProduct Properties: ProductName: WebServerComponent ProvisioningArtifactName: !Ref WebServerComponentVersion ProvisioningParameters: - Key: SystemId Value: !Ref SystemId - Key: VpcId Value: !GetAtt Network.Outputs.VpcId - Key: PublicSubnetAId Value: !GetAtt Network.Outputs.PublicSubnetAId - Key: PublicSubnetCId Value: !GetAtt Network.Outputs.PublicSubnetCId - Key: PrivateSubnetAId Value: !GetAtt Network.Outputs.PrivateSubnetAId - Key: PrivateSubnetCId Value: !GetAtt Network.Outputs.PrivateSubnetCId - Key: SGLoadBalancerId Value: !GetAtt SecurityGroup.Outputs.SGLoadBalancerId - Key: SGWebServerId Value: !GetAtt SecurityGroup.Outputs.SGWebServerId Database: Type: AWS::ServiceCatalog::CloudFormationProvisionedProduct Properties: ProductName: DatabaseComponent ProvisioningArtifactName: !Ref DatabaseComponentVersion ProvisioningParameters: - Key: SystemId Value: !Ref SystemId - Key: IsolatedSubnetAId Value: !GetAtt Network.Outputs.IsolatedSubnetAId - Key: IsolatedSubnetCId Value: !GetAtt Network.Outputs.IsolatedSubnetCId - Key: SGDatabaseId Value: !GetAtt SecurityGroup.Outputs.SGDatabaseId - Key: DatabaseAdminUserPassword Value: !Ref DatabaseAdminUserPassword
このテンプレートから製品名WebSystem
、バージョン名1.0
としてService Catalogの製品を作成します。
このテンプレートから起動される製品のテンプレートは以下の通りです。バージョン名は全て1.0
とします。
NetworkComponent
AWSTemplateFormatVersion: 2010-09-09 Parameters: SystemId: Type: String VpcCidr: Type: String Resources: # ------------------------------------------------------------# # VPC # ------------------------------------------------------------# Vpc: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCidr EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: !Sub ${SystemId}-vpc # ------------------------------------------------------------# # サブネット # ------------------------------------------------------------# PublicSubnetA: Type: AWS::EC2::Subnet Properties: VpcId: !Ref Vpc AvailabilityZone: ap-northeast-1a CidrBlock: !Select [ 0, !Cidr [ !Ref VpcCidr, 6, 6]] Tags: - Key: Name Value: !Sub ${SystemId}-public-subnet-a PublicSubnetC: Type: AWS::EC2::Subnet Properties: VpcId: !Ref Vpc AvailabilityZone: ap-northeast-1c CidrBlock: !Select [ 1, !Cidr [ !Ref VpcCidr, 6, 6]] Tags: - Key: Name Value: !Sub ${SystemId}-public-subnet-c PrivateSubnetA: Type: AWS::EC2::Subnet Properties: VpcId: !Ref Vpc AvailabilityZone: ap-northeast-1a CidrBlock: !Select [ 2, !Cidr [ !Ref VpcCidr, 6, 6]] Tags: - Key: Name Value: !Sub ${SystemId}-private-subnet-a PrivateSubnetC: Type: AWS::EC2::Subnet Properties: VpcId: !Ref Vpc AvailabilityZone: ap-northeast-1c CidrBlock: !Select [ 3, !Cidr [ !Ref VpcCidr, 6, 6]] Tags: - Key: Name Value: !Sub ${SystemId}-private-subnet-c IsolatedSubnetA: Type: AWS::EC2::Subnet Properties: VpcId: !Ref Vpc AvailabilityZone: ap-northeast-1a CidrBlock: !Select [ 4, !Cidr [ !Ref VpcCidr, 6, 6]] Tags: - Key: Name Value: !Sub ${SystemId}-isolated-subnet-a IsolatedSubnetC: Type: AWS::EC2::Subnet Properties: VpcId: !Ref Vpc AvailabilityZone: ap-northeast-1c CidrBlock: !Select [ 5, !Cidr [ !Ref VpcCidr, 6, 6]] Tags: - Key: Name Value: !Sub ${SystemId}-isolated-subnet-c # ------------------------------------------------------------# # インターネットゲートウェイ # ------------------------------------------------------------# InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Sub ${SystemId}-igw InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref Vpc InternetGatewayId: !Ref InternetGateway # ------------------------------------------------------------# # NATゲートウェイ # ------------------------------------------------------------# NatGatewayA: Type: AWS::EC2::NatGateway Properties: SubnetId: !Ref PublicSubnetA AllocationId: !GetAtt NatGatewayEipA.AllocationId Tags: - Key: Name Value: !Sub ${SystemId}-ngw-a NatGatewayC: Type: AWS::EC2::NatGateway Properties: SubnetId: !Ref PublicSubnetC AllocationId: !GetAtt NatGatewayEipC.AllocationId Tags: - Key: Name Value: !Sub ${SystemId}-ngw-c NatGatewayEipA: Type: AWS::EC2::EIP Properties: Tags: - Key: Name Value: !Sub ${SystemId}-ngw-eip-a NatGatewayEipC: Type: AWS::EC2::EIP Properties: Tags: - Key: Name Value: !Sub ${SystemId}-ngw-eip-c # ------------------------------------------------------------# # ルートテーブル # ------------------------------------------------------------# PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref Vpc Tags: - Key: Name Value: !Sub ${SystemId}-public-rtb PrivateRouteTableA: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref Vpc Tags: - Key: Name Value: !Sub ${SystemId}-private-rtb-a PrivateRouteTableC: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref Vpc Tags: - Key: Name Value: !Sub ${SystemId}-private-rtb-c IsolatedRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref Vpc Tags: - Key: Name Value: !Sub ${SystemId}-isolated-rtb PublicRouteTableAssociationA: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetA RouteTableId: !Ref PublicRouteTable PublicRouteTableAssociationC: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetC RouteTableId: !Ref PublicRouteTable PrivateRouteTableAssociationA: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PrivateSubnetA RouteTableId: !Ref PrivateRouteTableA PrivateRouteTableAssociationC: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PrivateSubnetC RouteTableId: !Ref PrivateRouteTableC IsolatedRouteTableAssociationA: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref IsolatedSubnetA RouteTableId: !Ref IsolatedRouteTable IsolatedRouteTableAssociationA: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref IsolatedSubnetC RouteTableId: !Ref IsolatedRouteTable RouteToInternetGateway: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway RouteToNatGatewayA: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTableA DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGatewayA RouteToNatGatewayC: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTableC DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGatewayC Outputs: VpcId: Value: !Ref Vpc PublicSubnetAId: Value: !Ref PublicSubnetA PublicSubnetCId: Value: !Ref PublicSubnetC PrivateSubnetAId: Value: !Ref PrivateSubnetA PrivateSubnetCId: Value: !Ref PrivateSubnetC IsolatedSubnetAId: Value: !Ref IsolatedSubnetA IsolatedSubnetCId: Value: !Ref IsolatedSubnetC
SecurityGroupComponent
AWSTemplateFormatVersion: 2010-09-09 Parameters: SystemId: Type: String VpcId: Type: String Resources: # ------------------------------------------------------------# # セキュリティグループ # ------------------------------------------------------------# SGLoadBalancer: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Load Balancer SG VpcId: !Ref VpcId SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 SecurityGroupEgress: - IpProtocol: "-1" CidrIp: 0.0.0.0/0 Tags: - Key: Name Value: !Sub ${SystemId}-loadbalancer-sg SGWebServer: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Web Server SG VpcId: !Ref VpcId SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !Ref SGLoadBalancer SecurityGroupEgress: - IpProtocol: "-1" CidrIp: 0.0.0.0/0 Tags: - Key: Name Value: !Sub ${SystemId}-web-server-sg SGDatabase: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Database SG VpcId: !Ref VpcId SecurityGroupIngress: - IpProtocol: tcp FromPort: 3306 ToPort: 3306 SecurityGroupEgress: - IpProtocol: "-1" CidrIp: 0.0.0.0/0 Tags: - Key: Name Value: !Sub ${SystemId}-database-sg Outputs: SGLoadBalancerId: Value: !Ref SGLoadBalancer SGWebServerId: Value: !Ref SGWebServer SGDatabaseId: Value: !Ref SGDatabase
WebServerComponent
AWSTemplateFormatVersion: 2010-09-09 Parameters: SystemId: Type: String VpcId: Type: String PublicSubnetAId: Type: String PublicSubnetCId: Type: String PrivateSubnetAId: Type: String PrivateSubnetCId: Type: String SGLoadBalancerId: Type: String SGWebServerId: Type: String Mappings: RegionMap: ap-northeast-1: ImageId: ami-05112363dbe951480 Resources: # ------------------------------------------------------------# # EC2インスタンス # ------------------------------------------------------------# WebServerInstanceA: Type: AWS::EC2::Instance Properties: SubnetId: !Ref PrivateSubnetAId InstanceType: t2.micro ImageId: !FindInMap - RegionMap - !Ref AWS::Region - ImageId SecurityGroupIds: - !Ref SGWebServerId Tags: - Key: Name Value: !Sub ${SystemId}-web-server-a WebServerInstanceC: Type: AWS::EC2::Instance Properties: SubnetId: !Ref PrivateSubnetCId InstanceType: t2.micro ImageId: !FindInMap - RegionMap - !Ref AWS::Region - ImageId SecurityGroupIds: - !Ref SGWebServerId Tags: - Key: Name Value: !Sub ${SystemId}-web-server-c # ------------------------------------------------------------# # ELB # ------------------------------------------------------------# TGWebServers: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Sub ${SystemId}-web-server-tg VpcId: !Ref VpcId TargetType: instance Protocol: HTTP ProtocolVersion: HTTP1 Port: 80 Targets: - Id: !Ref WebServerInstanceA - Id: !Ref WebServerInstanceC LBWebServers: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Sub ${SystemId}-web-server-lb Type: application Scheme: internet-facing Subnets: - !Ref PublicSubnetAId - !Ref PublicSubnetCId SecurityGroups: - !Ref SGLoadBalancerId LBWebServersListnener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: Protocol: HTTP Port: 80 LoadBalancerArn: !Ref LBWebServers DefaultActions: - Type: forward TargetGroupArn: !Ref TGWebServers
DatabaseComponent
AWSTemplateFormatVersion: 2010-09-09 Parameters: SystemId: Type: String IsolatedSubnetAId: Type: String IsolatedSubnetCId: Type: String SGDatabaseId: Type: String DatabaseAdminUserPassword: Type: String NoEcho: true Resources: # ------------------------------------------------------------# # RDS # ------------------------------------------------------------# RDSInstance: Type: AWS::RDS::DBInstance Properties: Engine: mysql EngineVersion: "8.0" DBInstanceClass: db.t3.micro StorageType: gp2 AllocatedStorage: 20 MultiAZ: false VPCSecurityGroups: - !Ref SGDatabaseId DBParameterGroupName: !Ref PGDatabase OptionGroupName: !Ref OGDatabase DBSubnetGroupName: !Ref DatabaseSubnetGroup MasterUsername: admin MasterUserPassword: !Ref DatabaseAdminUserPassword PGDatabase: Type: AWS::RDS::DBParameterGroup Properties: DBParameterGroupName: !Sub ${SystemId}-db-pg Description: MySQL Database PG Family: mysql8.0 OGDatabase: Type: AWS::RDS::OptionGroup Properties: OptionGroupName: !Sub ${SystemId}-db-og OptionGroupDescription: MySQL Database OG EngineName: mysql MajorEngineVersion: "8.0" DatabaseSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupName: !Sub ${SystemId}-db-subnet-group DBSubnetGroupDescription: MySQL Database SubnetGroup SubnetIds: - !Ref IsolatedSubnetAId - !Ref IsolatedSubnetCId
各製品の作成が完了したら、ポートフォリオを作成して製品を登録します。 以下のテンプレートをプロビジョニングしてポートフォリオを作成します。
ポートフォリオ
AWSTemplateFormatVersion: 2010-09-09 Parameters: AccessSystemPortfolioPrincipalArn: Type: String ProviderName: Type: String Mappings: Components: NetworkComponent: ProductId: <NetworkComponentの製品ID> SecurityGroupComponent: ProductId: <SecurityGroupComponentの製品ID> WebServerComponent: ProductId: <WebServerComponentの製品ID> DatabaseComponent: ProductId: <DatabaseComponentの製品ID> Systems: WebSystem: ProductId: <WebSystemの製品ID> Portfolios: ComponentsPortfolio: Name: Components SystemsPortfolio: Name: Systems Resources: # ------------------------------------------------------------# # ポートフォリオ # ------------------------------------------------------------# ComponentsPortfolio: Type: AWS::ServiceCatalog::Portfolio Properties: DisplayName: !FindInMap - Portfolios - ComponentsPortfolio - Name ProviderName: !Ref ProviderName AcceptLanguage: jp SystemsPortfolio: Type: AWS::ServiceCatalog::Portfolio Properties: DisplayName: !FindInMap - Portfolios - SystemsPortfolio - Name ProviderName: !Ref ProviderName AcceptLanguage: jp # ------------------------------------------------------------# # 製品の登録 # ------------------------------------------------------------# NetworkComponentAssociation: Type: AWS::ServiceCatalog::PortfolioProductAssociation Properties: PortfolioId: !Ref ComponentsPortfolio ProductId: !FindInMap - Components - NetworkComponent - ProductId AcceptLanguage: jp SecurityGroupComponentAssociation: Type: AWS::ServiceCatalog::PortfolioProductAssociation Properties: PortfolioId: !Ref ComponentsPortfolio ProductId: !FindInMap - Components - SecurityGroupComponent - ProductId AcceptLanguage: jp WebServerComponentAssociation: Type: AWS::ServiceCatalog::PortfolioProductAssociation Properties: PortfolioId: !Ref ComponentsPortfolio ProductId: !FindInMap - Components - WebServerComponent - ProductId AcceptLanguage: jp DatabaseComponentAssociation: Type: AWS::ServiceCatalog::PortfolioProductAssociation Properties: PortfolioId: !Ref ComponentsPortfolio ProductId: !FindInMap - Components - DatabaseComponent - ProductId AcceptLanguage: jp WebSystemAssociation: Type: AWS::ServiceCatalog::PortfolioProductAssociation Properties: PortfolioId: !Ref SystemsPortfolio ProductId: !FindInMap - Systems - WebSystem - ProductId AcceptLanguage: jp # ------------------------------------------------------------# # 起動制約 # ------------------------------------------------------------# NetworkComponentLaunchRoleConstraint: Type: AWS::ServiceCatalog::LaunchRoleConstraint Properties: LocalRoleName: !Ref ComponentsPortfolioAssociationRole PortfolioId: !Ref ComponentsPortfolio ProductId: !FindInMap - Components - NetworkComponent - ProductId AcceptLanguage: jp SecurityGroupComponentLaunchRoleConstraint: Type: AWS::ServiceCatalog::LaunchRoleConstraint Properties: LocalRoleName: !Ref ComponentsPortfolioAssociationRole PortfolioId: !Ref ComponentsPortfolio ProductId: !FindInMap - Components - SecurityGroupComponent - ProductId AcceptLanguage: jp WebServerComponentLaunchRoleConstraint: Type: AWS::ServiceCatalog::LaunchRoleConstraint Properties: LocalRoleName: !Ref ComponentsPortfolioAssociationRole PortfolioId: !Ref ComponentsPortfolio ProductId: !FindInMap - Components - WebServerComponent - ProductId AcceptLanguage: jp DatabaseComponentLaunchRoleConstraint: Type: AWS::ServiceCatalog::LaunchRoleConstraint Properties: LocalRoleName: !Ref ComponentsPortfolioAssociationRole PortfolioId: !Ref ComponentsPortfolio ProductId: !FindInMap - Components - DatabaseComponent - ProductId AcceptLanguage: jp WebSystemLaunchRoleConstraint: Type: AWS::ServiceCatalog::LaunchRoleConstraint Properties: LocalRoleName: !Ref SystemsPortfolioAssociationRole PortfolioId: !Ref SystemsPortfolio ProductId: !FindInMap - Systems - WebSystem - ProductId AcceptLanguage: jp # ------------------------------------------------------------# # ポートフォリオへのアクセス権限 # ------------------------------------------------------------# ComponentsPortfolioPrincipalAssociation: Type: AWS::ServiceCatalog::PortfolioPrincipalAssociation Properties: PortfolioId: !Ref ComponentsPortfolio PrincipalType: IAM PrincipalARN: !GetAtt SystemsPortfolioAssociationRole.Arn AcceptLanguage: jp SystemsPortfolioPrincipalAssociation: Type: AWS::ServiceCatalog::PortfolioPrincipalAssociation Properties: PortfolioId: !Ref SystemsPortfolio PrincipalType: IAM PrincipalARN: !Ref AccessSystemPortfolioPrincipalArn AcceptLanguage: jp # ------------------------------------------------------------# # 起動制約用のIAMロール # ------------------------------------------------------------# ComponentsPortfolioAssociationRole: Type: AWS::IAM::Role Properties: RoleName: components-portfolio-role AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - servicecatalog.amazonaws.com Action: - sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonEC2FullAccess - arn:aws:iam::aws:policy/AmazonRDSFullAccess - arn:aws:iam::aws:policy/AWSCloudFormationFullAccess - !Ref ServiceCatalogManagedBucketAccessPolicy SystemsPortfolioAssociationRole: Type: AWS::IAM::Role Properties: RoleName: systems-portfolio-role AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - servicecatalog.amazonaws.com Action: - sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/AWSServiceCatalogEndUserFullAccess - arn:aws:iam::aws:policy/AWSCloudFormationFullAccess - !Ref ServiceCatalogManagedBucketAccessPolicy ServiceCatalogManagedBucketAccessPolicy: Type: AWS::IAM::ManagedPolicy Properties: ManagedPolicyName: service-catalog-managed-bucket-access-policy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - s3:GetObject Resource: "*" Condition: StringEquals: s3:ExistingObjectTag/servicecatalog:provisioning: true
このテンプレートによりSystem
ポートフォリオとComponents
ポートフォリオが作成されます。System
ポートフォリオは製品WebSystem
のみを登録し、Components
ポートフォリオにはWebSystem
から起動される製品群が登録されます。
起動制約によりユーザーから起動できる製品をSystem
ポートフォリオに含まれる製品、すなわちWebSystem
のみに設定しています。
起動してみた
以下のパラメータでWebSystem
を起動します。
プロビジョニング完了後、複数の製品がプロビジョニングされていることが確認できました。
テンプレート分割をした製品について
CloudFormationProvisionedProductを使うことで製品どうしを組み合わせることができます。 その応用として、今回やったように製品から他製品を起動する(以下、ネスト起動)ことでテンプレートの分割をすることができます。
他にテンプレート分割をした製品を作成する方法として、下記ブログにあるようにネストスタックを行う方法があります。
この方法と比較して、今回のネスト起動によるテンプレート分割のメリット・デメリットを挙げていきます。
メリット
同じバージョンの製品で同じ構造のスタックがプロビジョニングされることを保証しやすい
ネストスタックを使った方法だと、Service Catalogの製品である参照元のテンプレートはバージョン管理されますが、S3バケットにある参照先のテンプレートはバージョン管理されていません。 そのため、同じバージョンの製品を同じパラメータで起動したとしても、参照先のテンプレートに更新があった場合に異なる構造のスタックがプロビジョニングされてしまう可能性があります。
その点、ネスト起動だと参照元と参照先の両方がバージョン管理されているため、同じ構造のスタックがプロビジョニングされることを保証しやすいです。
デメリット
Service Catalogの利用料金が増える
Service Catalogの利用料金はAPIの呼び出し回数によって決まるので、製品の起動回数が多いネスト起動の方が利用料金が増えます。
マルチリージョンでの管理が煩雑になる
Service Catalogはリージョン間で製品を共有することはできないので、他リージョンで製品を利用したい場合は製品を再作成する必要があります。
ネスト起動の場合は参照元と参照先の製品を再作成する必要がありますが、ネストスタックの場合は参照元のみを再作成するだけで済みます。
ネスト起動は管理する製品数が多いので、リージョン間で製品の同一性を管理するためのコストも増大します。
まとめ
CloudFormationProvisionedProductを使った製品起動を実際に試し、製品のテンプレート分割に関する考察を行いました。 CloudFormationProvisionedProductの利用の参考になれば幸いです。
他の利用例として以下のAWSブログ記事を挙げます。